<?php
/**
 *  An implementation of the WorkflowVisitor interface that
 * verifies a workflow specification.
 *
 * This visitor should not be used directly but will be used by the
 * verify() method on the workflow.
 *
 * <code>
 * <?php
 * $workflow->verify();
 * ?>
 * </code>
 *
 * The verifier checks that:
 * - there is only one start node
 * - there is only one finally node
 * - each node satisfies the constraints of the respective node type
 * @author dengdl
 *
 */
class Workflow_Visitor_Verification extends Workflow_Visitor
{
/**
     * Holds the number of start nodes encountered during visiting.
     *
     * @var integer
     */
    protected $numStartNodes = 0;

    /**
     * Holds the number of finally nodes encountered during visiting.
     *
     * @var integer
     */
    protected $numFinallyNodes = 0;

    /**
     * Perform the visit.
     *
     * @param Workflow_Visitable $visitable
     */
    protected function doVisit( Workflow_Visitable $visitable )
    {
        if ( $visitable instanceof Workflow_Definition )
        {
            foreach ( $visitable->nodes as $node )
            {
                if ( $node instanceof Workflow_Node_Start &&
                    !$node instanceof Workflow_Node_Finally )
                {
                    $this->numStartNodes++;

                    if ( $this->numStartNodes > 1 )
                    {
                        throw new Exception(
                          'A workflow may have only one start node.'
                        );
                    }
                }

                if ( $node instanceof Workflow_Node_Finally )
                {
                    $this->numFinallyNodes++;

                    if ( $this->numFinallyNodes > 1 )
                    {
                        throw new Exception(
                          'A workflow may have only one finally node.'
                        );
                    }
                }
            }
        }

        if ( $visitable instanceof Workflow_Node )
        {
            $visitable->verify();
        }
    }
}
?>